﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LightINI
{
    partial class Ini
    {
        /// <summary>
        /// 配置段
        /// </summary>
        [Serializable]
        public class Section : IEnumerable<Item>
        {
            [NonSerialized]
            public Ini Parent;

            /// <summary>
            /// 配置段名称
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 配置段下的配置项
            /// </summary>
            private readonly List<Item> Items;

            /// <summary>
            /// 配置项 数量
            /// </summary>
            public int Count => Items.Count;

            /// <summary>
            /// 配置段行末尾处的注释
            /// </summary>
            public string Comment { get; set; }

            /// <summary>
            /// 配置段前的空行与注释行，仅第一个配置段前有空行
            /// </summary>
            public string[] HeadRows { get; set; }

            /// <summary>
            /// 配置段后的空行与注释行
            /// </summary>
            public string[] TailRows { get; set; }

            /// <summary>
            /// 配置段是否可用（名称不为空）
            /// </summary>
            public bool Available => !string.IsNullOrWhiteSpace(Name);

            public Section() : this(null) { }

            public Section(Ini parent)
            {
                Parent = parent;
                Items = new List<Item>();
            }

            /// <summary>
            /// 读取配置项
            /// </summary>
            /// <param name="key">指定的键名称</param>
            /// <returns></returns>
            public Item Get(string key)
            {
                return Items.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
            }

            /// <summary>
            /// 读取配置项
            /// </summary>
            /// <param name="key">指定的键名称</param>
            /// <returns></returns>
            public Item Get(string key, string value)
            {
                return Items.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
            }

            /// <summary>
            /// 是否存在指定的配置项
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public bool Has(string key)
            {
                return Items.Any(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
            }

            /// <summary>
            /// 读取值
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public string GetValue(string key)
            {
                var item = Get(key);
                return item == null ? null : item.Value;
            }

            /// <summary>
            /// 设置值
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public void Set(string key, string value)
            {
                if (value == null)
                {
                    value = "";
                }
                var item = Get(key, value);
                if (item == null)
                {
                    item = new Item
                    {
                        Key = key,
                    };

                    EmitEvent(ChangeType.AddItem, item, () =>
                    {
                        Items.Add(item);
                    });
                }

                EmitEvent(ChangeType.EditItem, item, () =>
                {
                    item.Value = value.ToString();
                });
            }

            /// <summary>
            /// 设置值
            /// </summary>
            /// <param name="item"></param>
            public void Set(Item item)
            {
                if (item == null)
                {
                    return;
                }

                var oldItem = Get(item.Key);
                if (oldItem == null)
                {
                    EmitEvent(ChangeType.AddItem, item, () =>
                    {
                        Items.Add(item);
                    });
                    return;
                }
                EmitEvent(ChangeType.EditItem, item, () =>
                {
                    oldItem.Value = item.Value;
                    oldItem.Comment = item.Comment;
                    oldItem.HeadRows = item.HeadRows;
                });
            }

            /// <summary>
            /// 移除指定项
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public Item Remove(string key)
            {
                var found = Get(key);
                if (found != null)
                {
                    EmitEvent(ChangeType.RemoveItem, found, () =>
                    {
                        Items.Remove(found);
                    });
                }
                return found;
            }

            private void EmitEvent(ChangeType type, object target, Action action)
            {
                if (Parent == null)
                {
                    action.Invoke();
                    return;
                }
                Parent.EmitEvent(type, target, () =>
                {
                    action.Invoke();
                });
            }

            public override bool Equals(object obj)
            {
                return obj != null && Name.Equals(obj.ToString(), StringComparison.OrdinalIgnoreCase);
            }

            public override int GetHashCode()
            {
                return Name.GetHashCode();
            }

            public override string ToString()
            {
                StringBuilder buffer = new StringBuilder();
                if (HeadRows != null)
                {
                    foreach (var row in HeadRows)
                    {
                        buffer.AppendLine(row);
                    }
                }
                buffer.AppendLine(string.Format("[{0}] {1}", Name, Comment));

                foreach (var item in Items)
                {
                    buffer.AppendLine(item.ToString());
                }
                if (TailRows != null)
                {
                    foreach (var row in TailRows)
                    {
                        buffer.AppendLine(row);
                    }
                }

                buffer.AppendLine();
                return buffer.ToString();
            }

            public IEnumerator<Item> GetEnumerator()
            {
                return Items.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return Items.GetEnumerator();
            }

            /// <summary>
            /// 将一个类对象的字段设置到 IniSection 上
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public void Serielize<T>(T obj) where T : class
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// 从 IniSection 读取配置项的值，设置到 obj 对应的字段上
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            public void Deserielzie<T>(T obj) where T : class
            {
                throw new NotImplementedException();
            }
        }
    }
}
